﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;
using DeepTime.BootStrapper.UploadedImageMetaData;
using DeepTime.BootStrapper.Utilities;
using DeepTime.BootStrapper.DataModels;
using DeepTime.BootStrapper.DeepTimeImageMetaData;

namespace DeepTime.BootStrapper.Views
{
    public partial class DeepZoomViewer : Page
    {
        #region Class Members

        double zoom = 1.5;
        bool duringDrag = false;
        bool mouseDown = false;
        Point lastMouseDownPos = new Point();
        Point lastMousePos = new Point();
        Point lastMouseViewPort = new Point();

        #endregion Class Members

        public DeepZoomViewer()
        {
            InitializeComponent();

            //
            // Instantiate members
            //
            SubscribeToEvents();            
        }

        #region Override Methods

        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            ProcessQueryString();
        }

        #endregion Override Methods

        #region Methods

        /// <summary>
        /// Processes the query string
        /// </summary>
        private void ProcessQueryString()
        {
            bool ValidQueryString = true;

            //
            // Process query string
            //
            string rowKey = "";
            if (NavigationContext.QueryString["rowkey"] != null)
            {
                rowKey = NavigationContext.QueryString["rowkey"];
            }
            else
            {
                ValidQueryString = false;
            }

            string partitionKey = "";
            if (NavigationContext.QueryString["partitionkey"] != null)
            {
                partitionKey = NavigationContext.QueryString["partitionkey"];
            }
            else
            {
                ValidQueryString = false;
            }

            if (ValidQueryString)
            {
                LoadDeepZoom(rowKey, partitionKey);
            }
        }

        /// <summary>
        /// Loads the DeepZoom info
        /// </summary>
        private void LoadDeepZoom(string rowKey, string partitionKey)
        {
            DeepTimeImageMetaDataClient proxy = ServiceHelper.CreateDeepZoomImageMetaDataProxy();

            proxy.GetDeepZoomImageCompleted += delegate(object sender, GetDeepZoomImageCompletedEventArgs e)
            {
                SetDefaultView(e.Result.Height, e.Result.Width);
                this.DataContext = new DeepZoomImageMetaDataDataModel(e.Result);

            };

            proxy.GetDeepZoomImageAsync(rowKey, partitionKey);
        }

        /// <summary>
        /// Subscribes to events for which handle interaction with the multi scale image
        /// </summary>
        private void SubscribeToEvents()
        {
            //
            // Handling all of the mouse and keyboard functionality
            //
            this.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                lastMousePos = e.GetPosition(msiImage);

                if (duringDrag)
                {
                    Point newPoint = lastMouseViewPort;
                    newPoint.X += (lastMouseDownPos.X - lastMousePos.X) / msiImage.ActualWidth * msiImage.ViewportWidth;
                    newPoint.Y += (lastMouseDownPos.Y - lastMousePos.Y) / msiImage.ActualWidth * msiImage.ViewportWidth;
                    msiImage.ViewportOrigin = newPoint;
                }
            };

            this.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e)
            {
                lastMouseDownPos = e.GetPosition(msiImage);
                lastMouseViewPort = msiImage.ViewportOrigin;

                mouseDown = true;

                msiImage.CaptureMouse();
            };

            this.MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs e)
            {
                if (!duringDrag)
                {
                    bool shiftDown = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
                    double newzoom = zoom;

                    if (shiftDown)
                    {
                        newzoom /= 2;
                    }
                    else
                    {
                        newzoom *= 2;
                    }

                    Zoom(newzoom, msiImage.ElementToLogicalPoint(this.lastMousePos));
                }
                duringDrag = false;
                mouseDown = false;

                msiImage.ReleaseMouseCapture();
            };

            this.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                lastMousePos = e.GetPosition(msiImage);
                if (mouseDown && !duringDrag)
                {
                    duringDrag = true;
                    double w = msiImage.ViewportWidth;
                    Point o = new Point(msiImage.ViewportOrigin.X, msiImage.ViewportOrigin.Y);
                    msiImage.UseSprings = false;
                    msiImage.ViewportOrigin = new Point(o.X, o.Y);
                    msiImage.ViewportWidth = w;
                    zoom = 1 / w;
                    msiImage.UseSprings = true;
                }

                if (duringDrag)
                {
                    Point newPoint = lastMouseViewPort;
                    newPoint.X += (lastMouseDownPos.X - lastMousePos.X) / msiImage.ActualWidth * msiImage.ViewportWidth;
                    newPoint.Y += (lastMouseDownPos.Y - lastMousePos.Y) / msiImage.ActualWidth * msiImage.ViewportWidth;
                    msiImage.ViewportOrigin = newPoint;
                }
            };


            this.MouseWheel += delegate(object sender, MouseWheelEventArgs e)
            {
                e.Handled = true;

                double newzoom = zoom;

                if (e.Delta < 0)
                    newzoom /= 1.3;
                else
                    newzoom *= 1.3;

                Zoom(newzoom, msiImage.ElementToLogicalPoint(this.lastMousePos));
                msiImage.CaptureMouse();
            };
        }

        /// <summary>
        /// Zoom logic
        /// </summary>
        /// <param name="newzoom"></param>
        /// <param name="p"></param>
        private void Zoom(double newzoom, Point p)
        {
            if (newzoom < 0.1)
            {
                newzoom = 0.1;
            }

            msiImage.ZoomAboutLogicalPoint(newzoom / zoom, p.X, p.Y);
            zoom = newzoom;
        }

        /// <summary>
        /// Sets the multiscale image's default view
        /// </summary>
        /// <param name="ImageHeight"></param>
        /// <param name="ImageWidth"></param>
        private void SetDefaultView(long ImageHeight, long ImageWidth)
        {
            double ratio = msiImage.ActualHeight / msiImage.ActualWidth;

            msiImage.ViewportWidth = 5;

            double X = (msiImage.ViewportWidth / 2) - 0.5;
            double Y = (msiImage.ViewportWidth * ratio / 2) - (1 * ratio);

            msiImage.ViewportOrigin = new Point(-X, -Y);
        }

        #endregion Methods
    }
}